import pathchVnode from "./patchVnode";
import createElement from "./createElement";

// 判断是否是同一个虚拟节点
function checkSameVnode(a, b) {
  return (a.sel == b.sel && a.key == b.key);
}

export default function updateChildren(parentElm, oldCh, newCh) {
  console.log('我是updateChildren')

  console.log(oldCh, newCh)
  let oldStartIdx = 0; // 旧前
  let newStartIdx = 0; // 新前
  let oldEndIdx = oldCh.length - 1; // 旧后
  let newEndIdx = newCh.length - 1; // 新后
  let oldStartVnode = oldCh[0]; // 旧前节点
  let oldEndVnode = oldCh[oldEndIdx]; // 旧后节点
  let newStartVnode = newCh[0]; // 新前节点
  let newEndVnode = newCh[newEndIdx]; // 新后节点

  let keyMap = null; // 缓存

  while (newStartIdx <= newEndIdx && oldStartIdx <= oldEndIdx) {
    // console.log(oldStartIdx, oldStartVnode, newStartVnode)
    // 首先判断①②③④命中，而是略过已经加undefined标记的东西
    if (oldStartVnode == null || oldCh[oldStartIdx] == undefined) {
      oldStartVnode = oldCh[++oldStartIdx];
    } else if (oldEndVnode == null || oldCh[oldEndIdx] == undefined) {
      oldEndVnode = oldCh[--oldEndIdx];
    } else if (newStartVnode == null || newCh[newStartIdx] == undefined) {
      newStartVnode = newCh[++newStartIdx];
    } else if (newEndVnode == null || newCh[newEndIdx] == undefined) {
      newEndVnode = newCh[--newEndIdx];
    } else if (checkSameVnode(oldStartVnode, newStartVnode)) {
      console.log('①新前和旧前命中');
      pathchVnode(oldStartVnode, newStartVnode);
      oldStartVnode = oldCh[++oldStartIdx];
      newStartVnode = newCh[++newStartIdx];
    } else if (checkSameVnode(oldEndVnode, newEndVnode)) {
      console.log('②新后和旧后命中');
      pathchVnode(oldEndVnode, newEndVnode);
      oldEndVnode = oldCh[--oldEndIdx];
      newEndVnode = newCh[--newEndIdx];
    } else if (checkSameVnode(oldStartVnode, newEndVnode)) {
      console.log('③新后和旧前命中');
      pathchVnode(oldStartVnode, newEndVnode);
      // 当③新后和旧前命中的时候，此时要移动节点。移动新前指向这个节点到老节点的旧后的后面
      // 如何移动节点？？只要你插入一个已经在DOM树上的节点，它就会被移动
      parentElm.insertBefore(oldStartVnode.elm, oldEndVnode.elm.nextSibling);
      oldStartVnode = oldCh[++oldStartIdx];
      newEndVnode = newCh[--newEndIdx];
    } else if (checkSameVnode(oldEndVnode, newStartVnode)) {
      console.log('④新前和旧后命中');
      pathchVnode(oldEndVnode, newStartVnode);
      // 当③新后和旧前命中的时候，此时要移动节点。移动新前指向这个节点到老节点的旧后的后面
      parentElm.insertBefore(oldEndVnode.elm, oldStartVnode.elm.nextSibling);
      oldEndVnode = oldCh[--oldEndIdx];
      newStartVnode = newCh[++newStartIdx];
    } else {
      // 都没有匹配到的情况
      // 制作keyMap的一个映射对象，这样就不用每次都遍历对象了。
      if (!keyMap) {
        keyMap = {};
        for (let i = oldStartIdx; i <= oldEndIdx; i++) {
          const key = oldCh[i].key;
          if (key != undefined) {
            keyMap[key] = i;
          }
        }
      }
      console.log('keyMap', keyMap)
      // 寻找当前这项（newStartIdx）这项在keyMap中的映射位置序号。
      const idxInOld = keyMap[newStartVnode.key];
      console.log(idxInOld);
      if (idxInOld == undefined) {
        // 判断，如果idxInOld是undefined，说明它是全新的项；
        // 被加入的项（就是newStartVnode这项）还不是真正的DOM节点
        parentElm.insertBefore(createElement(newStartVnode), oldStartVnode.elm);
      } else {
        // 如果不是undefined，说明不是全新的项，而是移动
        const elmToMove = oldCh[idxInOld];
        pathchVnode(elmToMove, newStartVnode);
        // 把这项设置为undefined，表示已经处理完这项了
        oldCh[idxInOld] = undefined;
        // 移动，调用insertBefore也可以实现移动
        parentElm.insertBefore(elmToMove.elm, oldStartVnode.elm);
      }
      // 指针下移，只移动新的头
      newStartVnode = newCh[++newStartIdx];
      // newStartIdx++;
    }
  }
  // 循环结束后，
  // 继续看看有没有剩余的，循环结束了start还是比old小
  if (newStartIdx <= newEndIdx) {
    console.log('还有一些新节点')
    console.log(newStartIdx, newEndIdx)
    // 说明要插入这些节点
    const before = newCh[newEndIdx + 1] == undefined ? undefined : newCh[newEndIdx + 1].elm;
    for (let i = newStartIdx; i <= newEndIdx; i++) {
      // insertBefore方法可以自动识别null，如果是null就会自动排到队尾去，和appendChild是一致的。
      parentElm.insertBefore(createElement(newCh[i]), before);
    }
  } else if (oldStartIdx <= oldEndIdx) {
    console.log('还有一些老节点', oldStartIdx, oldEndIdx)
    console.log(oldCh, newCh)
    // 批量删除oldStart和oldEnd指针之间的项
    for (let i = oldStartIdx; i <= oldEndIdx; i++) {
      if (oldCh[i] != undefined) {
        parentElm.removeChild(oldCh[i].elm);
      }
    }
  }
}